package sf.database.dialect;

import sf.database.dbinfo.Feature;
import sf.database.meta.ColumnMapping;
import sf.database.support.DBMS;
import sf.jooq.JooqSupportDatabase;
import sf.querydsl.QueryDSLSupportDatabase;

import java.sql.Connection;

public interface IDBDialect {
    /**
     * @return 当前数据库类型，名称参见 DB 这个枚举类型
     * @see DBMS
     */
    String getName();

    /**
     * @return 当前数据库编号，名称参见 DB 这个枚举类型,自定义的不可和DB 枚举冲突
     */
    int getNumber();

    /**
     * 判断数据库是否不支持某项特性
     * @param feature
     * @return
     */
    boolean notHas(Feature feature);

    /**
     * 判断数据库是否支持某项特性
     * @param feature
     * @return
     */
    boolean has(Feature feature);

    /**
     * 像Oracle，其Catlog是不用的，那么返回null mySQL没有Schema，每个database是一个catlog，那么返回值
     * 同时修正返回的大小写
     * @param catalog
     * @return
     */
    String getCatalog(String catalog);

    /**
     * 对于表名前缀的XX. MYSQL是作为catlog的，不是作为schema的 同时修正返回的大小写
     * @param schema
     * @return
     */
    String getSchema(String schema);

    /**
     * 获取数据库的默认驱动类
     * @param url Derby根据连接方式的不同，会有两种不同的DriverClass，因此需要传入url
     * @return 驱动类
     */
    String getDriverClass(String url);

    /**
     * 检查数据库是否包含指定的关键字，用来进行检查的对象名称都是按照getColumnNameIncase转换后的，因此对于大小写统一的数据库，
     * 这里无需考虑传入的大小写问题。
     * @param name
     * @return
     */
    boolean containKeyword(String name);

    /**
     * Oracle会将所有未加引号的数据库对象名称都按照大写对象名来处理;MySQL则对表名一律转小写，列名则保留原来的大小写。
     * 为了体现这一数据库策略的不同，这里处理大小写的问题。
     * <p>
     * 目前的原则是：凡是涉及
     * schema/table/view/sequence/dbname等转换的，都是用此方法，凡是涉及列名转换，列别名定义的都用
     * {@link #getColumnNameToUse}方法
     * @param name
     * @return
     */
    String getObjectNameToUse(String name);

    /**
     * 获得大小写正确的列名
     * @param name
     * @return
     */
    String getColumnNameToUse(ColumnMapping name);

    long getColumnAutoIncreamentValue(ColumnMapping mapping, Connection db);

    /**
     * 不同数据库登录后，所在的默认schema是不一样的
     * <ul>
     * <li>Oracle是以登录的用户名作为schema的。</li>
     * <li>mysql是只有catlog不区分schema的。</li>
     * <li>derby支持匿名访问，此时好像是位于APP这个schema下。</li>
     * <li>SQL Server默认是在dbo这个schema下</li>
     * </ul>
     * <br>因此对于无法确定当前schema的场合，使用这里提供的schema名称作为当前schema
     * @return 当前RDBMS的缺省Schema
     */
    String getDefaultSchema();

    /**
     * 初始化方言，根据JDBC接口进一步嗅探出数据库版本和JDBC驱动信息，从而让方言更加适配数据库操作。
     * 当有一个数据库实例连接初次创建时调用. Dialect可以通过直接连接数据库判断版本、函数等，调整Dialect内部的一些配置和数据。
     * @param conn
     */
    void accept(Connection conn);

    /**
     * 数据库对象是否为大小写敏感的
     * 一般来说对应引号中的表名列名都是大小写敏感的。此处仅指没有引号的情况下是否大小写敏感
     * @return
     */
    boolean isCaseSensitive();

    default String getQueryDslDialect() {
        return QueryDSLSupportDatabase.SQLDEFAULT;
    }

    default String getJooqDialect() {
        return JooqSupportDatabase.DEFAULT;
    }
}
